#include <jni.h>
#include <string>
#include <android/log.h>
#include <stdlib.h>


#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)




extern "C" {

char *Jstring2Cstr(JNIEnv * env, jstring jstr){
    char * rtn = NULL;
    jclass  jclass1 = env->FindClass("java/lang/String");
    jstring strenCode  = env->NewStringUTF("GB2312");
    jmethodID  mid =  env->GetMethodID(jclass1,"getBytes","(Ljava/lang/String;)[B");
    jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strenCode);
    jsize  alen = env->GetArrayLength(barr);
    jbyte * ba = env->GetByteArrayElements(barr,JNI_FALSE);
    if (alen > 0){
        rtn = (char*)malloc(alen+1);//   "\0"
        memcpy(rtn, ba,alen);
    }
    env->ReleaseByteArrayElements(barr,ba,0);
    return rtn;
}

JNIEXPORT jint JNICALL
Java_com_wondersgroup_mylibrary_Util_multiplicative(JNIEnv *env, jobject instance, jint x, jint y) {

    // TODO
    return  x*y;
}


JNIEXPORT jint JNICALL
Java_com_wondersgroup_mylibrary_Util_getAddValue(JNIEnv *env, jobject instance, jint x, jint y) {
    LOGD("debug");
//    LOGI("info");

    const char * hello  = Jstring2Cstr(env, env->NewStringUTF("你好我的ndk"));
    printf("hello = %s",hello);
    //加载字节码
    //jcalss
    // ********注意包名间   /   *****
//    jclass  clazz = env->FindClass("com/wondersgroup/mylibrary/Util");
    jclass clazz = env->GetObjectClass(instance);
    //获取方法id
    //获取方法签名 javap - s    Util  在util。class  下使用
    //***************************调用方法************************
   jmethodID jmethodID1 =  env->GetMethodID(clazz, "showValue", "(Ljava/lang/String;)V");

    env->CallVoidMethod(instance,jmethodID1, env->NewStringUTF("jni 调用 java"));




    // TODO
    return  x+y;
}


JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_processArr(JNIEnv *env, jobject instance, jintArray arr_) {
    jint *arr = env->GetIntArrayElements(arr_, NULL);
    jint lenth = env->GetArrayLength(arr_);
    for (int i=0;i<lenth; i++){
        * (arr+i) += 10;
    }
    // TODO

    env->ReleaseIntArrayElements(arr_, arr, 0);
}

/*
GetStringUTFChars将jstring转换成为UTF-8格式的char*
GetStringChars将jstring转换成为Unicode格式的char*
ReleaseStringUTFChars释放指向UTF-8格式的char*的指针
ReleaseStringChars释放指向Unicode格式的char*的指针
NewStringUTF创建一个UTF-8格式的String对象
NewString创建一个Unicode格式的String对象
GetStringUTFLengt获取 UTF-8格式的char*的长度　
GetStringLength获取Unicode格式的char*的长 度
*/

JNIEXPORT jstring JNICALL
Java_com_wondersgroup_mylibrary_Util_getStringFromC(JNIEnv *env, jclass type) {

    // TODO
    char * cstr = (char *) "我是中国人";

//    jclass  jstrclass = env->FindClass("java/lang/String");
    jstring  str = env->NewStringUTF(cstr);
    env->ReleaseStringUTFChars(str,cstr);


    //************************访问静态变量******************
     jfieldID  staticfieldId = env->GetStaticFieldID(type,"count", "I");


    int count  = env->GetStaticIntField(type, staticfieldId);
    //************************设置静态变量******************

    env->SetStaticIntField(type,staticfieldId,30);

    //************************根据class  new 对象*******************************
//    jclass strClass = env->FindClass("java/lang/String");
    jmethodID  strConstructorid = env->GetMethodID(type,"<init>","()V");

     jobject  utilObject = env->NewObject(type,strConstructorid);



    //*****************访问变量***********************ß
    jfieldID  keyFieldid = env->GetFieldID(type,"key","Ljava/lang/String;");
    //********************设置变量的值**************************
    env->SetObjectField(utilObject,keyFieldid,env->NewStringUTF("hello   my ndk demo"));
    //********************取变量的值**************************
    jstring  keyStr = (jstring) env->GetObjectField(utilObject, keyFieldid);
    //*********************调用方法*******************************
    jmethodID showMethodId = env->GetMethodID(type,"showValue","(Ljava/lang/String;)V");
    env->CallVoidMethod(utilObject,showMethodId,keyStr);
    return str;
}


JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_chineseChars(JNIEnv *env, jobject instance, jstring str_) {

        char * ret = (char *) "马撒大声地";

        jclass strClass = env->FindClass("java/lang/String");
        jmethodID  jmethodID1 = env->GetMethodID(strClass,"<init>","([BLjava/lang/String;)V");

    jbyteArray  bytes = env->NewByteArray(strlen(ret));
    env->SetByteArrayRegion(bytes, 0, strlen(ret), (const jbyte *) ret);
jstring  charsetName= env->NewStringUTF("GB2312");
    jobject jobject1 =env->NewObject(strClass,jmethodID1,bytes,charsetName);

}

/**
 * c层创建数组
 *
 */
JNIEXPORT jobjectArray JNICALL
Java_com_wondersgroup_mylibrary_Util_initStringArray(JNIEnv *env, jobject instance, jint size) {

    // TODO
    jclass  strCls = env->FindClass("java/lang/String");
    if (strCls == NULL){
        return NULL;
    }


    jobjectArray  array = env->NewObjectArray(size,strCls,NULL);

    if (array == NULL){
        return NULL;
    }
    for (int i=0;i<size;i++){
//        char  cstrarr [128];
        char* cstrarr = (char *) malloc(128 * sizeof(char));
        memset(cstrarr,0,128);
        sprintf(cstrarr,"数组中第%d",i);
        jstring  itemStr = env->NewStringUTF(cstrarr);
        if (itemStr == NULL){
            return NULL;
        }
        env->SetObjectArrayElement(array,i,itemStr);
        free(cstrarr);
        cstrarr = NULL;
        env->DeleteLocalRef(itemStr);
    }
    return  array;
}

int compare(const void* a, const void* b){
    void *x = &a;
    void *y = &b;
    return  *(jint*)x - *(jint*)y;
}

/**
 * c 进行快速排序
 */
JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_sortArrary(JNIEnv *env, jobject instance, jintArray arr_) {
    jint *arr = env->GetIntArrayElements(arr_, NULL);
    if (arr == NULL){
        return;
    }
    jsize  length = env->GetArrayLength(arr_);
    qsort(arr,length, sizeof(jint),compare);
    // TODO
    //释放可能的内存
    //将jni 修改的数据重新写回原来的内存
    env->ReleaseIntArrayElements(arr_, arr, JNI_COMMIT);
}

/**
 * jni local ref  局部引用
 * 定义方式多样  findclass newobjhect getobjectclass    newlocalref  ...
 * 释放方式   方法调用完  jvm会自动释放   DeleteLocalRef
 */
JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_localRef(JNIEnv *env, jobject instance) {

    // TODO
    for (int i=0; i<5;i++){
        jclass  dateCls = env->FindClass("java/util/Date");
        jmethodID  constructId = env->GetMethodID(dateCls,"<init>","()V");
        jobject  item = env->NewObject(dateCls,constructId);
        env->DeleteLocalRef(dateCls);
        env->DeleteLocalRef(item);

    }
}




jobject  globalStr;
/**
 * 创建全局引用
 * 夸线程夸方法
 */
JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_createGlobalref(JNIEnv *env, jobject instance) {

    if (globalStr == NULL){
        jobject jobject1 = env->NewStringUTF("global string");
        globalStr = env->NewGlobalRef(jobject1);
    }
    // TODO


}
JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_delGlobalref(JNIEnv *env, jobject instance) {

    // TODO
    if (globalStr != NULL){
        env->DeleteGlobalRef(globalStr);
        globalStr = NULL;
    }

}

/**
 * 弱引用
 * 不会阻止gc 跨线程 夸方法
 */
jobject  globalWeakRef;
JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_createWeakRef(JNIEnv *env, jobject instance) {

    // TODO
    if (globalWeakRef == NULL){
        jobject  jobject1 = env->NewStringUTF("gloabal weak ref");
        globalWeakRef = env->NewWeakGlobalRef(jobject1);
    }
}


JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_exception(JNIEnv *env, jobject instance) {

    // TODO
   jclass  cls = env->GetObjectClass(instance);
   jthrowable  ex = env->ExceptionOccurred();

    jfieldID  jfieldID1 = env->GetFieldID(cls, "key1", "java/lang/String;");

    if (ex !=NULL){
        jclass strCls = env->FindClass("java/lang/IllegalArgumentException");
        if (strCls ==NULL){
            return;
        }
        env->ThrowNew(strCls,"throw exception from jni");

    }
    env->ExceptionDescribe();//输出关于异常的描述
   env->ExceptionClear();
}


JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_cached(JNIEnv *env, jobject instance) {

    // TODO
    jclass cls = env->GetObjectClass(instance);
    static jfieldID  fid= NULL;
    if (fid == NULL){
        fid = env->GetFieldID(cls,"key","Ljava/lang/String;");
    }

}


jfieldID  fidGlb;
JNIEXPORT void JNICALL
Java_com_wondersgroup_mylibrary_Util_gloablCached(JNIEnv *env, jobject instance) {

    jclass  jclass1 = env->GetObjectClass(instance);
    // TODO
    fidGlb = env->GetFieldID(jclass1,"key","Ljava/lang/String;");
}

}